package concurrent.lock.condition;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 线程之间的通信
 * Lock的Condition可以指定唤醒某个线程
 * 吃饭 -》 拉屎 -》 睡觉 -》 吃饭的循环 一一执行
 *
 * @author LoneRanger
 */
public class ShareResourceDemo {
	public static void main(String[] args) {

		ShareResource shareResource = new ShareResource();

		new Thread(() -> {
			for (int i = 0; i < 10; i++) {
				shareResource.eat();
			}
		}, "线程0").start();

		new Thread(() -> {
			for (int i = 0; i < 10; i++) {
				shareResource.shit();
			}
		}, "线程1").start();

		new Thread(() -> {
			for (int i = 0; i < 10; i++) {
				shareResource.sleep();
			}
		}, "线程2").start();
	}
}

class ShareResource {

	/**
	 * 执行的顺序是 0 1 2
	 * num = 0的时候eat 执行
	 * num = 1的时候shit 执行
	 * num = 2的时候sleep 执行
	 */
	private int num = 0;

	/**
	 * 一个可重入锁
	 */
	private Lock lock = new ReentrantLock();

	/**
	 * 三个钥匙
	 */
	private Condition condition0 = lock.newCondition();

	private Condition condition1 = lock.newCondition();

	private Condition condition2 = lock.newCondition();

	/**
	 * 吃饭，吃完饭拉屎
	 */
	public void eat() {
		lock.lock();
		try {
			while (num != 0) {
				condition0.await();
			}

			System.out.println(Thread.currentThread().getName() + "eat");

			num = 1;

			condition1.signal();

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	/**
	 * 拉屎，拉完屎，睡觉
	 */
	public void shit() {
		lock.lock();
		try {
			while (num != 1) {
				condition1.await();
			}

			System.out.println(Thread.currentThread().getName() + "shit");

			num = 2;

			condition2.signal();

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	/**
	 * 睡觉，睡完觉吃饭
	 */
	public void sleep() {
		lock.lock();
		try {
			while (num != 2) {
				condition2.await();
			}

			System.out.println(Thread.currentThread().getName() + "sleep");

			num = 0;

			condition0.signal();

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}


}
